﻿//===============================================================================
//	LuaManager.cpp
//	C++ -> LUA接口管理器
//===============================================================================

#include <cstdarg>
#include <fstream>

#include "LuaManager.h"
#include "../share/user_define.h"
#include "LuaGlue.h"

#include "LuaScriptManager.h"

//-------------------------------------------------------------------------------
LuaManager::StackStep::StackStep( void )
{
	_safe_guard_begin;

	Reset();

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
LuaManager::StackStep::~StackStep( void )
{
	Reset();
}

//-------------------------------------------------------------------------------
void LuaManager::StackStep::Reset( void )
{
	_safe_guard_begin;

	m_script_id = invalid_int32_value;
	memset(m_function_name, 0, size_256);

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
LuaManager::LuaStack::LuaStack( void )
{
	_safe_guard_begin;

	Reset();

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
LuaManager::LuaStack::~LuaStack( void )
{
	Reset();
}

//-------------------------------------------------------------------------------
void LuaManager::LuaStack::Reset( void )
{
	_safe_guard_begin;

	m_current_step = 0;
	for ( int i = 0; i < s_max_stack_step; ++i )
	{
		m_step[i].Reset();
	}

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
bool LuaManager::LuaStack::StepStart( const char* functionName, int32_t scriptId )
{
	_safe_guard_begin;

	if ( m_current_step >= s_max_stack_step )
	{
		LOG_ERROR("default","Out of lua manager stack !!! %d, %s", scriptId, functionName);
		return false;
	}

	m_step[m_current_step].m_script_id = scriptId;
	strncpy(m_step[m_current_step].m_function_name, functionName, size_256 -1 );
	++m_current_step;

	return true;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
bool LuaManager::LuaStack::StepEnd( void )
{
	_safe_guard_begin;

	if ( m_current_step <= 0 )
	{
		LOG_ERROR("default","Low lua manager stack !!!");
		return false;
	}

	--m_current_step;

	return true;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
void LuaManager::LuaStack::DisplayStack( void )
{
	_safe_guard_begin;

	for ( int32_t i = m_current_step - 1; i >= 0; --i )
	{
		//printf(">>> Stack : scriptID[%d] : FunctionName : %s\n", 
		//	m_step[i].m_script_id, m_step[i].m_function_name);

		LOG_INFO("default",">>> Stack : scriptID[%d] : FunctionName : %s",
			m_step[i].m_script_id, m_step[i].m_function_name);
	}

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
int32_t LuaManager::LuaStack::GetCurrentStepCount( void )
{
	_safe_guard_begin;

	return m_current_step;

	_safe_guard_end;

	return invalid_int32_value;
}

//-------------------------------------------------------------------------------
//LuaManager& LuaManager::GetInstance( void )
//{
//	static LuaManager s_instance;
//	return s_instance;
//}

//-------------------------------------------------------------------------------
LuaManager::LuaManager( void )
	: m_state(nullptr)
{
	_safe_guard_begin;
	LOG_INFO("default","LuaManager create.");

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
LuaManager::~LuaManager( void )
{

}

//-------------------------------------------------------------------------------
bool LuaManager::Initialize( void )
{
	_safe_guard_begin;
	LOG_INFO("default","LuaManager Initialize. idx=%d", m_idx);

	m_state = lua_open();
	if ( ! m_state )
	{
		scriptError(ScriptCreateError);
		return false;
	}

	luaL_openlibs(m_state);

	for ( int i = 0; LuaGlueDef[i].name; ++i)
	{
		lua_register( m_state, LuaGlueDef[i].name, LuaGlueDef[i].func );
	}

	return true;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
bool LuaManager::Exit( void )
{
	_safe_guard_begin;

	if(m_state)
	{
		lua_close(m_state);
		m_state = nullptr;
	}
	
	return true;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
bool LuaManager::LoadScript( const char *file_name )
{
	_safe_guard_begin;

	LOG_INFO("default","LoadScript %s ...", file_name);

	std::ifstream _fin;
	_fin.open(file_name);
	if ( ! _fin.is_open() )
	{
		memset(m_temp_str, 0, size_256);
		snprintf(m_temp_str, size_256 - 1, "Load Script no file %s.\n", file_name);

		_safe_check_ex(false, m_temp_str);

		return false;
	}
	_fin.close();

	if ( CheckResult(luaL_loadfile(m_state, file_name)) != LUA_OK )
	{
		memset(m_temp_str, 0, size_256);
		snprintf(m_temp_str, size_256 - 1, "Load Script luaL_loadfile error %s. Error:%s\n",
			file_name, LUA_ERROR_MESSAGE);
		_safe_check_ex(false, m_temp_str);

		return false;
	}

	int ret = 0;
	try {
		ret = lua_pcall(m_state, 0, 0, 0);
	}
	catch (...)
	{
		ret = 1;
		LOG_ERROR("default","LuaManager::LoadScript lua_pcall err! file_name=%s. Error:%s", file_name, LUA_ERROR_MESSAGE);
	}

	if ( CheckResult(ret) != LUA_OK )
	{
		memset(m_temp_str, 0, size_256);
		snprintf(m_temp_str, size_256 - 1, "Load Script lua_pcall error %s. Error:%s\n",
			file_name, LUA_ERROR_MESSAGE);
		_safe_check_ex(false, m_temp_str);

		return false;
	}

	LOG_INFO("default","LoadScript %s OK!", file_name);
	return true;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
bool LuaManager::TryLock(void)
{
	_safe_guard_begin;

	if (!m_atomic_bool) 
	{
		LOG_ERROR("default","TryLock FALSE!! last function=%s", m_full_function_name);
	}

	return m_atomic_bool;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
bool LuaManager::RegisterFunction( char* function_name, LuaFunctionType function )
{
	lua_register(m_state, function_name, function);
	return true;
}

//-------------------------------------------------------------------------------
void LuaManager::scriptError( int32_t errCode )
{
	_safe_guard_begin;

	//memset(m_temp_str, 0, size_256);

	//snprintf(m_temp_str, size_256 - 1, "ScriptError %d.\n", errCode);
	//fprintf(stderr, m_temp_str);
	LOG_ERROR("default","ScriptError %d.", errCode, errCode);

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
void LuaManager::scriptError( int32_t errCode, int32_t retCode )
{
	_safe_guard_begin;

	
	//memset(m_temp_str, 0, size_256);

	//snprintf(m_temp_str, size_256 - 1, "ScriptError %d:[%d].\n", errCode, retCode);
	//fprintf(stderr, m_temp_str);
	LOG_ERROR("default","ScriptError %d:[%d].", errCode, retCode);

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
void LuaManager::runScriptFunctionStart( int32_t& idx )
{
	_safe_guard_begin;

	if ( ! m_state )
	{
		return;
	}

	idx = lua_gettop(m_state);

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
void LuaManager::runScriptFunctionEnd( int32_t idx )
{
	_safe_guard_begin;

	if ( ! m_state )
	{
		return;
	}

	lua_settop(m_state, idx);

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
int32_t LuaManager::CheckResult( int32_t retCode )
{
	_safe_guard_begin;

	if ( LUA_OK != retCode )
	{
		switch (retCode)
		{
		case LUA_ERRFILE:
		case LUA_ERRSYNTAX:
			memset(m_temp_str, 0, size_256);
			snprintf(m_temp_str, size_256 - 1, "%s\n", lua_tostring(m_state, -1));
			fprintf(stderr, m_temp_str);
			LOG_ERROR("default","%s", m_temp_str);
			break;
		case LUA_ERRMEM:
			memset(m_temp_str, 0, size_256);
			snprintf(m_temp_str, size_256 - 1, 
				"Error code : LUA_ERRMEM, memory allocation error.\n");
			fprintf(stderr, m_temp_str);
			LOG_ERROR("default","%s", m_temp_str);
			break;
		case LUA_ERRERR:
			memset(m_temp_str, 0, size_256);
			snprintf(m_temp_str, size_256 - 1, 
				"Error code : LUA_ERRERR, error while running the message handle.\n");
			fprintf(stderr, m_temp_str);
			LOG_ERROR("default","%s", m_temp_str);
			break;
		case LUA_ERRRUN:
			memset(m_temp_str, 0, size_256);
			snprintf(m_temp_str, size_256 - 1, 
				"Error code : LUA_ERRRUN, tunning time error.\n %s\n", lua_tostring(m_state, -1));
			fprintf(stderr, m_temp_str);
			LOG_ERROR("default","%s", m_temp_str);
			break;
		default:
			memset(m_temp_str, 0, size_256);
			snprintf(m_temp_str, size_256 - 1, "Unkonw error code %d\n", retCode);
			fprintf(stderr, m_temp_str);
			LOG_ERROR("default","%s", m_temp_str);
			break;
		}
	}

	return retCode;

	_safe_guard_end;

	return LUA_ERRRUN;
}

//-------------------------------------------------------------------------------
bool LuaManager::findFunction( const char* functionName )
{
	_safe_guard_begin;

	//	lua_getglobal， 将全局变量functionName的值压栈（5.3 返回该值得类型）
	lua_getglobal(m_state, functionName);

	if ( lua_isnil(m_state, -1) )
	{
		lua_pop(m_state, 1);
		return false;
	}
	else
	{
		lua_pop(m_state, 1);
		return true;
	}

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
bool LuaManager::verifyFunction( int32_t scriptID, const char* functionName )
{
	_safe_guard_begin;

	memset(m_full_function_name, 0, size_256);

	if ( ! m_state )
	{
		scriptError(ScriptStateIsNullptr);
		return false;
	}

	snprintf(m_full_function_name, size_256 - 1, "S%05d_%s", scriptID, functionName);

	if ( ! findFunction(m_full_function_name) )
	{
// 		char* _cp = strchr(m_full_function_name, '_') + 1;
// 		memmove(m_full_function_name, _cp, strlen(_cp) + 1);
// 
// 		if ( ! findFunction(m_full_function_name) )
// 		{
#ifdef _DEBUG
			memset(m_temp_str, 0, size_256);

// 			lua_getglobal(m_state, static_LUA_Script_Step_Filename);
// 			const char* _filename = lua_tostring(m_state, 1);
//			lua_pop(m_state, 1);

			snprintf(m_temp_str, size_256 - 1, 
				"Can not find %s in %s.\n", m_full_function_name, m_full_filename);

			_safe_check_ex(false, m_temp_str);
#endif
			return false;
//		}
	}

	return true;

	_safe_guard_end;
	return  false;
}

//-------------------------------------------------------------------------------
void LuaManager::markScriptName( const char* scriptName )
{
#ifdef _DEBUG
	_safe_guard_begin;

	memset(m_full_filename, 0, size_256);

	if ( nullptr == scriptName)
	{
		return;
	}

	strncpy(m_full_filename, scriptName, strlen(scriptName));

// 	if ( ! m_state )
// 	{
// 		scriptError(ScriptStateIsNullptr);
// 		return;
// 	}
//	
// 	lua_pushstring(m_state, scriptName);
// 
// 	//	lua_setglobal在堆栈上弹出一个值，并将其设为全局变量static_LUA_Script_Step_Filename的新值
// 	lua_setglobal(m_state, static_LUA_Script_Step_Filename);

	_safe_guard_end;
#endif
}

//-------------------------------------------------------------------------------
bool LuaManager::verifyScriptFile(const char* file )
{
	_safe_guard_begin;

	if ( file )
	{
		return true;
	}

	memset(m_temp_str, 0, size_256);
	snprintf(m_temp_str, size_256 - 1, 
		"Verify Script File Error : File : %s\n", file );
	fprintf(stderr, m_temp_str);
	LOG_ERROR("default","%s", m_temp_str);
	return false;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
bool LuaManager::CheckParamCount( int32_t count, const char* functionName )
{
	_safe_guard_begin;

	if ( ! m_state )
	{
		scriptError(ScriptStateIsNullptr);
		return false;
	}

	int32_t _count = lua_gettop(m_state);
	if ( _count != count )
	{
		memset(m_temp_str, 0, size_256);
		snprintf(m_temp_str, size_256 - 1, 
			"LuaManager CheckParamCount ERROR : function [%s] count [%d] vs [%d].\n",
			functionName, count, _count );
		fprintf(stderr, m_temp_str);
		LOG_ERROR("default","%s", m_temp_str);
		m_stack.DisplayStack();

		return false;
	}

	return true;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
bool LuaManager::ReloadScript( int32_t scriptId )
{
	_safe_guard_begin;

	char* _script_filename = nullptr;

	bool _ret = LoadScript(_script_filename);
	if ( ! _ret )
	{

	}

	return _ret;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
bool LuaManager::IsNumber( int32_t idx, const char* functionName )
{
	_safe_guard_begin;

	if ( ! m_state )
	{
		scriptError(ScriptStateIsNullptr);
		return false;
	}

	if ( ! lua_isnumber(m_state, idx) )
	{
		memset(m_temp_str, 0, size_256);
		snprintf(m_temp_str, size_256 - 1, 
			"LuaManager ERROR : function [%s] %d is not number.\n", 
			functionName, idx );
		fprintf(stderr, m_temp_str);
		LOG_ERROR("default","%s", m_temp_str);
		m_stack.DisplayStack();

		return false;
	}

	return true;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
bool LuaManager::IsString( int32_t idx, const char* functionName )
{
	_safe_guard_begin;

	if ( ! m_state )
	{
		scriptError(ScriptStateIsNullptr);
		return false;
	}

	if ( ! lua_isstring(m_state, idx) )
	{
		memset(m_temp_str, 0, size_256);
		snprintf(m_temp_str, size_256 - 1, 
			"LuaManager ERROR : function [%s] %d is not string.\n",
			functionName, idx );
		fprintf(stderr, m_temp_str);
		LOG_ERROR("default","%s", m_temp_str);
		m_stack.DisplayStack();

		return false;
	}

	return true;

	_safe_guard_end;

	return false;
}

//-------------------------------------------------------------------------------
void LuaManager::StartStep(int32_t scriptId, const char* functionName )
{
	_safe_guard_begin;

	if ( static_Record_Script_Step )
	{
		int32_t _top = lua_gettop(m_state);
		int32_t _satck_size = m_stack.GetCurrentStepCount();

		memset(m_temp_str, 0, size_256);
		snprintf(m_temp_str, size_256 - 1, 
			"Start Function : [%08d]%s; top index : %d ; stack size : %d\n", 
			scriptId, m_full_function_name, _top, _satck_size );
		//printf(m_temp_str);
		LOG_INFO("default","%s", m_temp_str);
	}

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
void LuaManager::EndStep(int32_t scriptId, const char* functionName )
{
	_safe_guard_begin;

	if ( static_Record_Script_Step )
	{
		int32_t _top = lua_gettop(m_state);
		int32_t _satck_size = m_stack.GetCurrentStepCount();

		memset(m_temp_str, 0, size_256);
		snprintf(m_temp_str, size_256 - 1, 
			"End Function : [%08d]%s; top index : %d ; stack size : %d\n", 
			scriptId, m_full_function_name, _top, _satck_size );
		//printf(m_temp_str);
		LOG_INFO("default","%s", m_temp_str);
	}

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
const char * LuaManager::GetStringArgument( int32_t num, const char *val /*= nullptr*/ )
{
	_safe_guard_begin;

	return luaL_optstring(m_state, num, val);

	_safe_guard_end;

	return nullptr;
}

//-------------------------------------------------------------------------------
double LuaManager::GetNumberArgument( int32_t num, double def /*= 0.0*/ )
{
	_safe_guard_begin;

	return luaL_optnumber(m_state, num, def);
	
	_safe_guard_end;

	return 0.0;
}

//-------------------------------------------------------------------------------
int32_t LuaManager::GetIntegerArgument( int32_t num, int32_t def /*= 0*/ )
{
	_safe_guard_begin;

	return (int32_t)(luaL_optinteger(m_state, num, def));

	_safe_guard_end;

	return 0;
}

void LuaManager::SetIndex(uint32_t _val)
{
	m_idx = _val;
}

//-------------------------------------------------------------------------------
void LuaManager::PushString( const char *val )
{
	_safe_guard_begin;

	lua_pushstring(m_state, val);

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
void LuaManager::PushNumber( double val )
{
	_safe_guard_begin;

	lua_pushnumber(m_state, val);

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
void LuaManager::PushInteger( int32_t val )
{
	_safe_guard_begin;

	lua_pushinteger(m_state, val);

	_safe_guard_end;
}

//-------------------------------------------------------------------------------
int32_t LuaManager::runFileFunction( const char* filename, char* function_name, 
	const char* flag, ... )
{
	_safe_guard_begin; 

	m_atomic_bool = false;
//	std::lock_guard<std::mutex> _lock(m_mutex);

	int32_t _top_idx = 0; 
	int32_t _result = 0; 

	runScriptFunctionStart(_top_idx); 
	
	{
		va_list _vl;

		va_start(_vl, flag);

		int32_t argc_in = 0;
		lua_getglobal(m_state, function_name);
		for ( argc_in; *flag; ++argc_in )
		{
			luaL_checkstack(m_state, 1, "too many arguments");

			switch (*flag++)
			{
			case 'd':
			case 'D':
				PushNumber(va_arg(_vl, double));
				break;

			case 'i':
			case 'I':
				PushInteger(va_arg(_vl, int32_t));
				break;

			case 's':
			case 'S':
				PushString(va_arg(_vl, char*));
				break;

			case '>':
				goto endpush;
				break;

			default:
				break;
			}
		}

	endpush:
		
//		va_end(_vl);

		int32_t argc_out = (uint32_t)(strlen(flag));
		if (argc_out > 0)
		{
			int ret = 0;
			try {
				ret = lua_pcall(m_state, argc_in, argc_out, 0);
			}
			catch (...)
			{
				LOG_ERROR("default","runFileFunction 1 lua_pcall error! filename=%s function_name=%s. Error:%s", filename, function_name, LUA_ERROR_MESSAGE);
				ret = 1;
			}
			
			if ( ret != 0 )
			{
		 		if( ( LUA_TSTRING == lua_type(m_state, -1 ) ) )
		 		{
		 			char buf[256];
		 			snprintf( buf, 256, "Lua Error - Script Run\nScript Name:%s\n. Error:%s\n", function_name, luaL_checkstring(m_state, -1));
		 			fprintf(stderr, buf);

					LOG_ERROR("default","%s", buf);

					lua_pop(m_state, 1); 
		 		}
			}
		 
			argc_out = -argc_out;
			while ( *flag )
			{
		 		switch (*flag++)
		 		{
		 		case 'd':
		 		case 'D':
		 			if ( ! lua_isnumber(m_state, argc_out))
		 			{
		 				char buf[256];
		 				snprintf( buf, 256, "Lua Error - Script Run\nScript Name:%s wrong result double type", function_name );
		 				fprintf(stderr, buf);

						LOG_ERROR("default","%s", buf);
		 			}
		 			*va_arg(_vl, double*) = lua_tonumber(m_state, argc_out);
		 			break;
		 
		 		case 'i':
		 		case 'I':
		 			if ( ! lua_isnumber(m_state, argc_out))
		 			{
		 				char buf[256];
		 				snprintf( buf, 256, "Lua Error - Script Run\nScript Name:%s wrong result integer type", function_name );
		 				fprintf(stderr, buf);

						LOG_ERROR("default","%s", buf);
		 			}
		 			*va_arg(_vl, int32_t*) = (uint32_t)(lua_tointeger(m_state, argc_out));
		 
		 			break;
		 
		 		case 's':
		 		case 'S':
				{
					if (!lua_isstring(m_state, argc_out))
					{
						char buf[256];
						snprintf(buf, 256, "Lua Error - Script Run\nScript Name:%s wrong result string type", function_name);
						fprintf(stderr, buf);

						LOG_ERROR("default","%s", buf);
					}
					//*va_arg(_vl, const char**) = lua_tostring(m_state, argc_out);

					int str_len = lua_strlen(m_state, argc_out);
					const char* str_src = lua_tostring(m_state, argc_out);
					char* str_dest = va_arg(_vl, char *);

					// 如果有输入长度，接取最大长度吧
					const char *sig_next = flag;
					if (*sig_next == 'n')
					{
						int input_len = va_arg(_vl, int);
						if (input_len > 0 && input_len < str_len)
						{
							str_len = input_len;
						}
						flag++;
					}

					// 执行内存拷贝
					memcpy(str_dest, str_src, str_len);
				}
		 			break;
		 		default:
		 			char buf[256];
		 			snprintf( buf, 256, "Lua Error - Script Run\nScript Name:%s wrong result string type. Error:%s", function_name, LUA_ERROR_MESSAGE);
		 			fprintf(stderr, buf);

					LOG_ERROR("default","%s", buf);
		 		}
		 
		 		++argc_out;
			}
		}
		else
		{
			int32_t _ret = 0;
			try {
				_ret = lua_pcall(m_state, argc_in, 1, 0);
			}
			catch (...)
			{
				LOG_ERROR("default","runFileFunction 2 lua_pcall error! filename=%s function_name=%s. Error:%s", filename, function_name, LUA_ERROR_MESSAGE);
				_ret = 1;
			}
			if (CheckResult(_ret) != LUA_OK)
			{
				scriptError(ScriptRunError, _ret);
				memset(m_temp_str, 0, size_256);
				snprintf(m_temp_str, size_256 - 1, "Lua run script function err [%s : %s] : %s.\n", filename, function_name, LUA_ERROR_MESSAGE);
				fprintf(stderr, m_temp_str);

				LOG_ERROR("default","%s", m_temp_str);
			}
			else
			{

				if (!lua_isnumber(m_state, -1))
				{
					memset(m_temp_str, 0, size_256);
					snprintf(m_temp_str, size_256 - 1,
						"lua_pcall return error :file : %s; function %s is return %s.\n",
						filename, function_name, LUA_ERROR_MESSAGE);
					fprintf(stderr, m_temp_str);
					LOG_ERROR("default","%s", m_temp_str);
				}
				else
				{
					_result = GetIntegerArgument(-1);
				}
			}
		}

		va_end(_vl);

	} 

	runScriptFunctionEnd(_top_idx); 

	m_atomic_bool = true;

	return _result; 

	_safe_guard_end; 

	return  0;
}

//-------------------------------------------------------------------------------
std::string LuaManager::runFileFunctionStringRet(const char* filename, char* function_name, const char* flag, ...)
{
	_safe_guard_begin;

	m_atomic_bool = false;
	//	std::lock_guard<std::mutex> _lock(m_mutex);

	int32_t _top_idx = 0;
	std::string _result = "";

	runScriptFunctionStart(_top_idx);


	{
		va_list _vl;

		va_start(_vl, flag);

		int32_t argc_in = 0;
		lua_getglobal(m_state, function_name);
		for (argc_in; *flag; ++argc_in)
		{
			luaL_checkstack(m_state, 1, "too many arguments");

			switch (*flag++)
			{
			case 'd':
			case 'D':
				PushNumber(va_arg(_vl, double));
				break;

			case 'i':
			case 'I':
				PushInteger(va_arg(_vl, int32_t));
				break;

			case 's':
			case 'S':
				PushString(va_arg(_vl, char*));
				break;

			case '>':
				goto endpush;
				break;

			default:
				break;
			}
		}

	endpush:

		//		va_end(_vl);

		int32_t argc_out = (uint32_t)(strlen(flag));
		if (argc_out > 0)
		{
			if (lua_pcall(m_state, argc_in, argc_out, 0) != 0)
			{
				if ((LUA_TSTRING == lua_type(m_state, -1)))
				{
					char buf[256];
					snprintf(buf, 256, "Lua Error - Script Run\nScript Name:%s\nError Message:%s error:%s\n", function_name, luaL_checkstring(m_state, -1), LUA_ERROR_MESSAGE);
					fprintf(stderr, buf);
					lua_pop(m_state, 1);
				}
			}

			argc_out = -argc_out;
			while (*flag)
			{
				switch (*flag++)
				{
				case 'd':
				case 'D':
					if (!lua_isnumber(m_state, argc_out))
					{
						char buf[256];
						snprintf(buf, 256, "Lua Error - Script Run\nScript Name:%s wrong result double type %s\n", function_name, LUA_ERROR_MESSAGE);
						fprintf(stderr, buf);
					}
					*va_arg(_vl, double*) = lua_tonumber(m_state, argc_out);
					break;

				case 'i':
				case 'I':
					if (!lua_isnumber(m_state, argc_out))
					{
						char buf[256];
						snprintf(buf, 256, "Lua Error - Script Run\nScript Name:%s wrong result integer type %s\n", function_name, LUA_ERROR_MESSAGE);
						fprintf(stderr, buf);
					}
					*va_arg(_vl, int32_t*) = (uint32_t)(lua_tointeger(m_state, argc_out));

					break;

				case 's':
				case 'S':
					if (!lua_isstring(m_state, argc_out))
					{
						char buf[256];
						snprintf(buf, 256, "Lua Error - Script Run\nScript Name:%s wrong result string type %s\n", function_name, LUA_ERROR_MESSAGE);
						fprintf(stderr, buf);
					}
					*va_arg(_vl, const char**) = lua_tostring(m_state, argc_out);
					break;

				default:
					char buf[256];
					snprintf(buf, 256, "Lua Error - Script Run\nScript Name:%s wrong result string type %s\n", function_name, LUA_ERROR_MESSAGE);
					fprintf(stderr, buf);
				}

				++argc_out;
			}
		}
		else
		{
			int32_t _ret = lua_pcall(m_state, argc_in, 1, 0);
			if (CheckResult(_ret) != LUA_OK)
			{
				scriptError(ScriptRunError, _ret);
				memset(m_temp_str, 0, size_256);
				snprintf(m_temp_str, size_256 - 1, "Lua run script function err [%s : %s] : %s.\n", filename, function_name, LUA_ERROR_MESSAGE);
				fprintf(stderr, m_temp_str);
			}
			else
			{

				if (!lua_isstring(m_state, -1))
				{
					memset(m_temp_str, 0, size_256);
					snprintf(m_temp_str, size_256 - 1,
						"lua_pcall return error :file : %s; function %s is return %s.\n",
						filename, function_name, LUA_ERROR_MESSAGE);
					fprintf(stderr, m_temp_str);
				}
				else
				{
					_result = GetStringArgument(-1);
					printf("lua_pcall return : %s \n", _result.c_str());
				}
			}
		}

		va_end(_vl);

	}

	runScriptFunctionEnd(_top_idx);

	m_atomic_bool = true;

	return _result;

	_safe_guard_end;

	return "";
}